#include <iostream>
#include <cstring>
#include <unistd.h>
#include <cstdio>
#include <cstdlib>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <errno.h>

using namespace std;
// g++ test.cc -o test -std=c++11

#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <cassert>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include "Task.hpp"
using namespace std;

#define PROCESS_NUM 5

typedef pair<pid_t, int> slot;

void sendCommand(int fatherWriter, uint32_t command_ref)
{
    // ssize_t write(int __fd, const void *__buf, size_t __n)
    write(fatherWriter, &command_ref, sizeof(command_ref));
}

int getCommand(int childReader, bool &quit)
{
    uint32_t command_ref = 0;

    // ssize_t read(int __fd, void *__buf, size_t __nbytes)
    ssize_t s = read(childReader, &command_ref, sizeof(command_ref));
    if (s == 0)
    {
        quit = true;
        return -1;
    }
    assert(s == sizeof(uint32_t));

    return command_ref;
}

int main()
{
    Load();

    vector<pair<pid_t, int>> slots;

    for (int i = 0; i < PROCESS_NUM; i++)
    {
        int pipefd[2] = {0};
        int n = pipe(pipefd);
        assert(n == 0);
        (void)n;

        pid_t id = fork();
        assert(id != -1);

        if (id == 0)
        {
            close(pipefd[1]);

            while (true)
            {
                bool quit = false;
                int command_ref = getCommand(pipefd[0], quit);
                if (quit == true)
                    break;

                if (command_ref >= 0 && command_ref < cmdSetsize())
                    cmdSet[command_ref]();
                else
                    cout << "非法command: " << command_ref << endl;
            }

            exit(1);
        }

        close(pipefd[0]);
        slots.push_back(pair<pid_t, int>(id, pipefd[1]));
    }

    srand((unsigned long)time(nullptr) ^ getpid() ^ 23323123123L);
    while (true)
    {
        int command_ref = rand() % cmdSetsize();
        int child_ref = rand() % slots.size();

        sendCommand(slots[child_ref].second, command_ref);

        cout << "father[" << getpid() << "] call child[" << slots[child_ref].first
             << "] execute " << cmdContent[command_ref]
             << " through fatherWriter " << slots[child_ref].second << endl;

        sleep(1);
    }

    for (const auto &slot : slots)
        close(slot.second);

    for (const auto &slot : slots)
        waitpid(slot.first, nullptr, WNOHANG);
}
